package com.vision.sales.cl.ui;

import java.util.Collections;

import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.Event;
import com.sencha.gxt.core.client.IdentityValueProvider;
import com.sencha.gxt.core.client.Style.SelectionMode;
import com.sencha.gxt.widget.core.client.event.RowClickEvent;
import com.sencha.gxt.widget.core.client.event.RowMouseDownEvent;
import com.sencha.gxt.widget.core.client.event.XEvent;
import com.sencha.gxt.widget.core.client.grid.CheckBoxSelectionModel;
import com.sencha.gxt.widget.core.client.grid.GridSelectionModel;

/**
 * Custom {@link CheckBoxSelectionModel} implementation that achieves the normal
 * behaviors of a grid with a checkbox selection column, namely:
 * <ul>
 * 	<li>When a row is clicked and the column clicked is not the checkbox column, the selected (checked) rows are not changed.
 * GXT {@link CheckBoxSelectionModel}'s default behavior changes the rows selected (checked). 
 * 	<li>
 * </ul>
 * 
 * @author Mark
 * 
 * TODO Move to com.vision.core project when already stable.
 *
 * @param <M>
 */
public class CustomCheckBoxSelectionModel<M> extends CheckBoxSelectionModel<M> {

	public CustomCheckBoxSelectionModel(IdentityValueProvider<M> valueProvider) {
		super(valueProvider);
	}
	
	/**
	 * Custom implementation for handling row mouse down events. Most of the code
	 * is just copied from {@link GridSelectionModel#handleRowMouseDown(RowMouseDownEvent)}
	 * with a few minor tweaks to suit the required behavior.
	 * 
	 * @param event
	 */
	@Override
	protected void handleRowMouseDown(RowMouseDownEvent event) {
		if (Element.is(event.getEvent().getEventTarget())
				&& !grid.getView().isSelectableTarget(
						Element.as(event.getEvent().getEventTarget()))) {
			return;
		}
		if (isLocked()) {
			return;
		}
		
		XEvent e = event.getEvent().<XEvent> cast();
		
		int rowIndex = event.getRowIndex();
		int colIndex = event.getColumnIndex();
		
		if (rowIndex == -1) {
			return;
		}
		
		// NOTE Check if the cell clicked is the checkbox cell
		Element target = event.getEvent().getEventTarget().cast();
		if (!target.getClassName().equals("x-grid-row-checker")) {
			grid.getView().focusCell(rowIndex, colIndex, false);
			return;
		}

		if (event.getEvent().getButton() == Event.BUTTON_RIGHT) {
			if (selectionMode != SelectionMode.SINGLE
					&& isSelected(listStore.get(rowIndex))) {
				return;
			}
			grid.getView().focusCell(rowIndex, colIndex, false);
			select(rowIndex, false);
		} else {
			M sel = listStore.get(rowIndex);
			if (selectionMode == SelectionMode.SIMPLE) {
				if (!isSelected(sel)) {
					grid.getView().focusCell(rowIndex, colIndex, false);
					select(sel, true);
				}

			} else if (selectionMode == SelectionMode.SINGLE) {
				if (e.getCtrlOrMetaKey() && isSelected(sel)) {
					deselect(sel);
				} else if (!isSelected(sel)) {
					grid.getView().focusCell(rowIndex, colIndex, false);
					select(sel, false);
				}
			} else if (!e.getCtrlOrMetaKey()) {
				if (event.getEvent().getShiftKey() && lastSelected != null) {
					int last = listStore.indexOf(lastSelected);
					int index = rowIndex;
					grid.getView().focusCell(index, colIndex, false);
					select(last, index, e.getCtrlOrMetaKey());
				} else {
					if (!isSelected(sel)) {
						grid.getView().focusCell(rowIndex, colIndex, false);
						doSelect(Collections.singletonList(sel), true, false); // keepExisting set to true
					} else { // NOTE Added this else clause
						deselect(sel); // NOTE Deselect the model/row
					}
				} 
			}
		}
	}

	/**
	 * Custom implementation for handling row click events. Most of the code
	 * is just copied from {@link GridSelectionModel#handleRowClick(RowClickEvent)}
	 * with a few minor tweaks to suit the required behavior.
	 * 
	 * @param event
	 */
	@Override
	protected void handleRowClick(RowClickEvent event) {
		if (Element.is(event.getEvent().getEventTarget())
				&& !grid.getView().isSelectableTarget(
						Element.as(event.getEvent().getEventTarget()))) {
			return;
		}
		if (isLocked()) {
			return;
		}

		XEvent xe = event.getEvent().<XEvent> cast();

		int rowIndex = event.getRowIndex();
		int colIndex = event.getColumnIndex();
		if (rowIndex == -1) {
			deselectAll();
			return;
		}
		
		// NOTE Check if the cell clicked is the checkbox cell
		Element target = event.getEvent().getEventTarget().cast();
		if (!target.getClassName().equals("x-grid-row-checker")) {
			return;
		}
		
		if (selectionMode == SelectionMode.MULTI) {
			M sel = listStore.get(rowIndex);
			if (xe.getCtrlOrMetaKey() && isSelected(sel)) {
				doDeselect(Collections.singletonList(sel), false);
			} else if (xe.getCtrlOrMetaKey()) {
				grid.getView().focusCell(rowIndex, colIndex, false);
				doSelect(Collections.singletonList(sel), true, false);
			} else if (isSelected(sel) && !event.getEvent().getShiftKey()
					&& !xe.getCtrlOrMetaKey() && selected.size() > 1) {
				grid.getView().focusCell(rowIndex, colIndex, false);
				doSelect(Collections.singletonList(sel), true, false); // NOTE keepExisting set to true
			}
		}

	}
}